import java.io.File;
import java.io.FileFilter;
import java.util.List;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.atomic.AtomicInteger;


public class IndexService {
	public final static File POISON_PILL = new File("");
	private final Thread[] indexers;
	private final int MAX_FILES_IN_QUEUE;
	private final BlockingDeque<File>[] deques;
	private final Thread[] crawlers;
	private final CountDownLatch cdl;

	private AtomicInteger state;
	
	@SuppressWarnings("unchecked")	//Burn in hell M. Odersky!
	public IndexService(int consumers, int maxFilesInQueue, File[] roots, FileFilter filter) {
		indexers = new Thread[consumers];
		MAX_FILES_IN_QUEUE = maxFilesInQueue;
		deques = (BlockingDeque<File>[])new Object[consumers];
		for (int i = 0; i < indexers.length; i++) {
			BlockingDeque<File> deque = new LinkedBlockingDeque<File>(MAX_FILES_IN_QUEUE);
			deques[i] = deque;
			indexers[i] = new Thread(new Indexer(deque, deques));
			indexers[i].start();
		}
		crawlers = new Thread[roots.length];
		cdl = new CountDownLatch(roots.length);
		for (int i = 0; i < roots.length; ++i)
			crawlers[i] = new Thread(new FileCrawler(deques, filter, roots[i], cdl, POISON_PILL));
		state.set(0);
	}
	
	public void startIndexing(File[] roots, FileFilter filter) {
		if (!state.compareAndSet(0, 1))
			throw new IllegalStateException("Indexing is already started!");
		for (int i = 0; i < crawlers.length; ++i) {
			crawlers[i].start();
		}
		state.set(2);
	}
	
	public static void main(String[] args) {
		FileFilter filter = new FileFilter() {
			public boolean accept(File file) {
				return true;
			}
		};
	}


	public void waitUntilEnd() {
		if (state.get() != 2) throw new IllegalStateException();
		for (Thread indexer : indexers) {
			try {
				indexer.join();
			} catch (InterruptedException e) {
				break;
			}
		}
	}
	
	public void stopIndexing() {
		if (!state.compareAndSet(2, 3))
			throw new IllegalStateException();
		for (Thread th : crawlers) {
			th.interrupt();
		}
	}
}